from Config import *
import os
import codecs
import subprocess
import shlex
import lorun
import torndb

def get_code(code,work_path, real_path):
    try:
        os.mkdir(work_path)
    except OSError as e:
        if str(e).find("exist")>0:
            pass
        else:
            return False
    f = codecs.open(real_path, "w")
    f.write(code)
    f.close()

def check_danger_code(real_path, language):
    if language in ['python2', 'python3']:
        code = file(real_path).readlines()
        support_modules = [
            're',
            'sys',
            'string',
            'scanf',
            'math',
            'cmath',
            'decimal',
            'numbers',
            'fractions',
            'random',
            'itertools',
            'functools',
            'operator',
            'readline',
            'json',
            'array',
            'sets',
            'queue',
            'types',
            ]
        for line in code:
            if line.find('import') >= 0:
                words = line.split()
                tag = 0
                for w in words:
                    if w in support_modules:
                        tag = 1
                        break
                if tag == 0:
                    return False
        return True
    if language in ['c', 'c++']:
        try:
            code = file(real_path).read()
        except:
            code = file(real_path).read()
        if code.find('system') >= 0:
            return False
        return True

def compile_code(work_path, language):
    p = subprocess.Popen(
        compile_command[language],
        shell=True,
        cwd=work_path,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE)
    out, err = p.communicate()
    if p.returncode == 0:
        return True
    else:
        return False

def judge_one(work_path, pid,language):
    try:
        db = torndb.Connection(db_host, db_name, user = db_user, password= db_password)
    except:
        return False
    question_info = db.get("select * from problems where pid=" + str(pid))
    time_limit = question_info.timelimit
    mem_limit = question_info.memlimit
    input_data = question_info.input
    output_data = question_info.output

    f = codecs.open(os.path.join(work_path, "input.txt"), "w")
    f.write(input_data)
    f.close()

    input_data = file(os.path.join(work_path, "input.txt"))
    output_data = file(os.path.join(work_path, "output.txt"), "w")

    if language == 'c' or language == 'c++':
        main_exe = [os.path.join(work_path, 'main'), ]
    elif language == 'python2':
        cmd = 'python2 %s' % (os.path.join(work_path,'main.pyc'))
        main_exe = shlex.split(cmd)
    elif language == 'python3':
        cmd = 'python3 %s' % (os.path.join(work_path,'__pycache__/main.cpython-34.pyc'))
        main_exe = shlex.split(cmd)
    
    runcfg = {
        'args': main_exe,
        'fd_in': input_data.fileno(),
        'fd_out': output_data.fileno(),
        'timelimit': time_limit,
        'memorylimit': mem_limit*1024,
    }
    rst = lorun.run(runcfg)
    return rst

def judge_main(work_path, pid):
    answer = file(os.path.join(work_path, "output.txt")).read()
    try:
        db = torndb.Connection(db_host, db_name, user = db_user, password= db_password)
    except:
        return False
    correct = (db.get("select * from problems where pid="+str(pid))).output
    correct = correct.replace('\r', '')
    p_answer = answer.replace('\n', '')
    p_correct = correct.replace('\n', '')

    if correct == answer:
        return "accepted"
    elif p_correct == p_answer:
        return "presentation error"
    else:
        return "wrong answer"
    

def judge(runid, pid, cid, code, author, language):
    result = {
    "statu" : "system error",
    "runtime" : "0",
    "runmem" : "0",
    }
    
    work_path = os.path.join(system_dir, str(author),str(runid))
    real_path = os.path.join(work_path, file_name[str(language)])
    flag = get_code(code, work_path, real_path)
    if flag == False:
        return False
    flag = check_danger_code(real_path, language)
    if flag == False:
        result["statu"] = "restrict function"
        return result

    flag = compile_code(work_path, language)
    if flag == False:
        result["statu"] = "compile error"
        return result

    rst = judge_one(work_path, pid, language)
    if rst == False:
        return False
    elif rst['result'] == 5:
        result["statu"] = "run time error"
        return result
    elif rst['result'] == 2:
        result["statu"] = "time limit"
        return result
    elif rst['result'] == 3:
        result["statu"] = "memory limit"
        return result

    flag = judge_main(work_path, pid)
    if flag == False:
        return False

    result["runtime"] = rst["timeused"]
    result["runmem"] = rst['memoryused']
    result["statu"] = flag

    return result
